#include <QCoreApplication>
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFile>
#include <stdio.h>
#include <stdbool.h>

#include "configfile.h"
//#include "download.h"

enum status_e{
    NO_ERROR = 0,
    REQUEST_ERROR,
    FILE_ERROR,
};
void print_help();
slots void downloadResponse(QNetworkReply *reply);

ConfigFile *settings = nullptr;
QString localDir;
QNetworkRequest *baseRequest;
QNetworkAccessManager *netManager;
QString networkDir;
QStringList commandLineParamList, filenameList;
static int downloadFinishedCount = 0;
static int downloadFileListSize = 0;


int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    settings = new ConfigFile(QCoreApplication::applicationDirPath() + "/" + DEFAULT_FILENAME);
    netManager = new QNetworkAccessManager();
    baseRequest = new QNetworkRequest();

    QObject::connect(netManager,
                     &QNetworkAccessManager::finished,
                     &downloadResponse);

    if(argc < 4) {
        print_help();
        return -1;
    }

    /* init config, check config file */
    printf("Check 'config.ini' configuration parameters.\n");
    if(settings->value(USER_NAME).toString().length() == 0) {
        printf("%s %s is null.\n", __FUNCTION__, USER_NAME);
        return -2;
    }
    if(settings->value(USER_PHPSESSID).toString().length() == 0) {
        printf("%s %s is null.\n", __FUNCTION__, USER_PHPSESSID);
        return -2;
    }
    if(settings->value(USER_WEB_URL).toString().length() == 0) {
        printf("%s %s is null.\n", __FUNCTION__, USER_WEB_URL);
        return -2;
    }

    /* print command line param */
    commandLineParamList = app.arguments();
    printf("Parse Command Line Param:\n");
    for(int i = 0; i < commandLineParamList.size(); i++) {
        printf("%d:%s\n", i, commandLineParamList.at(i).toLatin1().data());
    }
    printf("\n");

    /* parse command param to var */
    printf("Initializing local variables.\n");
    networkDir = commandLineParamList.at(1);
    localDir = commandLineParamList.at(2);
    for(int i = 3; i < commandLineParamList.size(); i++) {
        filenameList.append(commandLineParamList.at(i));
    }
    if(filenameList.isEmpty()) {
        printf("%s filenameList is empty.", __FUNCTION__);
        return -3;
    }

    /* init request param */
    printf("Initializing request parameters.\n");
    baseRequest->setRawHeader("Cookie", QString("PHPSESSID=%1; secros_user_language=zh_CN; secros_name=%2")
                         .arg(settings->value(USER_PHPSESSID).toString())
                         .arg(settings->value(USER_NAME).toString())
                         .toUtf8());
    baseRequest->setHeader(QNetworkRequest::UserAgentHeader, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                                                        "AppleWebKit/537.36 (KHTML, like Gecko) Chrome"
                                                        "/104.0.0.0 Safari/537.36");
    baseRequest->setRawHeader("Host", settings->value(USER_WEB_URL).toString().mid(7).toUtf8());
    baseRequest->setRawHeader("Referer", QString("%1/index.php")
                         .arg(settings->value(USER_WEB_URL).toString()).toUtf8());
    QList<QByteArray> requestHeaderList = baseRequest->rawHeaderList();

    printf("Print the parameters of the request header:\n");
    for(int i = 0; i < requestHeaderList.size(); i++) {
        printf("%s : %s\n",
               requestHeaderList.at(i).data(),
               baseRequest->rawHeader(requestHeaderList.at(i)).data());
    }
    printf("\n");


    /* start downlaod */
    printf("The download task starts.\n");
    downloadFileListSize = filenameList.size();
#if 0
    for(int i = 0; i < filenameList.size(); i++) {
        /* Start concatenating the requested URL. */
        /* http://filegeli.timechicken.cc/index.php?explorer/fileDownload&path=/libGbtsTask.so */
        QString url;
        QNetworkRequest req = request;
        url += settings->value(USER_WEB_URL).toString();
        url += QString("/index.php?explorer/fileDownload&path=%1%2")
                .arg(networkDir)
                .arg(filenameList.at(i));
        req.setUrl(QUrl(url));
        printf("Start request '%s' .\n", url.toLatin1().data());
        /* start downlaod task */
        isDownloading = true;
        netManager->get(req);
    }
#endif
    QString url;
    QNetworkRequest req = *baseRequest;
    url += settings->value(USER_WEB_URL).toString();
    url += QString("/index.php?explorer/fileDownload&path=%1%2")
            .arg(networkDir)
            .arg(filenameList.takeFirst());
    req.setUrl(QUrl(url));
    printf("Start request '%s' .\n", url.toLatin1().data());
    netManager->get(req);

    return app.exec();
}

slots void downloadResponse(QNetworkReply *reply) {
    qDebug() << __FUNCTION__;
    /* 过滤请求错误 */
    if(reply->error() != QNetworkReply::NoError) {
        printf("%s %s \n", __FUNCTION__, reply->errorString().toLatin1().data());
        QCoreApplication::exit(REQUEST_ERROR);
    }

    /* 判断响应数据 */
    QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
    /* 如果解析响应状态码错误或者状态码!=200 */
    printf("%s Response statusCode:%d\n", __FUNCTION__, statusCode.toInt());
    if(!statusCode.isValid() || statusCode.toInt() != 200) {
        QVariant reason =  reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute);
        if(reason.isValid())
            printf("%s %s \n", __FUNCTION__, reason.toString().toLatin1().data());
        else
            printf("%s Unknown response error \n", __FUNCTION__);
        QCoreApplication::exit(REQUEST_ERROR);
    }

    /* parse response data */
    printf("Print the parameters of the response header:\n");
    QList<QByteArray> replyHeadersList = reply->rawHeaderList();
    for(int i = 0; i < replyHeadersList.size(); i++) {
        QByteArray headerByteArray = replyHeadersList.at(i);
        printf("%s : %s\n",
               headerByteArray.data(),
               reply->rawHeader(headerByteArray).data());
    }
    QString contentDisposition_Header = QString(reply->rawHeader("Content-Disposition"));
    int fileNameIndex = contentDisposition_Header.indexOf("filename=");
    fileNameIndex += QString("filename=").length();
    QString fileName = contentDisposition_Header.mid(fileNameIndex);
    QString downloadPath = localDir + "/" + fileName;
    printf("%s Downloaded file path: %s\n", __FUNCTION__, downloadPath.toLatin1().data());

    /* save data to file */
    QFile file(downloadPath);
    bool isOpen = file.open(QIODevice::WriteOnly);
    if(!isOpen) {
        printf("%s Open '%s' error:%s\n",
               __FUNCTION__,
               downloadPath.toLatin1().data(),
               file.errorString().toUtf8().data());
        QCoreApplication::exit(FILE_ERROR);
    }
    int writeLen = file.write(reply->readAll());
    printf("%s '%s' writed %d bytes.\n", __FUNCTION__, downloadPath.toLatin1().data(), writeLen);
    file.close();
    printf("\n\n\n");

    downloadFinishedCount++;
    if(filenameList.isEmpty() || downloadFinishedCount == downloadFileListSize) {
        printf("Downloading Done.\n");
//        filenameList << "null";
        QCoreApplication::exit(NO_ERROR);
        return ;
    }

//    QThread::usleep(500 * 1000); // 爬虫缓冲
    QString url;
    QNetworkRequest req = *baseRequest;
    url += settings->value(USER_WEB_URL).toString();
    url += QString("/index.php?explorer/fileDownload&path=%1%2")
            .arg(networkDir)
            .arg(filenameList.takeFirst());
    req.setUrl(QUrl(url));
    printf("Start request '%s' .\n", url.toLatin1().data());
    netManager->get(req);
}

void print_help() {
    printf("usage :\n");
    printf("DownloadProcess (network dir) (local dir) (file list)\n");
    printf("Refer to the source code for more paths.\n");
}
